<?php

namespace app\index\controller;

use think\Controller;
use app\index\model\Upload as UpModel;

class Upload extends Controller
{
    public function upload()
    {
        //$t1 = microtime(true);
        header("Access-Control-Allow-origin:*");
        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
        header("Cache-Control: no-store, no-cache, must-revalidate");
        header("Cache-Control: post-check=0, pre-check=0", false);
        header("Pragma: no-cache");
        if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
            exit;
        }

        if (!empty($_REQUEST['debug'])) {
            $random = rand(0, intval($_REQUEST['debug']));
            if ($random === 0) {
                header("HTTP/1.0 500 Internal Server Error");
                exit;
            }
        }
        @set_time_limit(0);

        $targetDir = 'upload_tmp';
        $uploadDir = 'upload';

        $cleanupTargetDir = true; //删除旧文件
        $maxFileAge = 5 * 3600; // 以秒为单位的临时文件大小
        if (!file_exists($targetDir)) {
            @mkdir($targetDir);
        }
        if (!file_exists($uploadDir)) {
            @mkdir($uploadDir);
        }
        if (isset($_REQUEST["name"])) {
            $fileName = $_REQUEST["name"];
            $size=$_REQUEST["size"];
        } elseif (!empty($_FILES)) {
            $fileName = $_FILES["file"]["name"];
            $size=$_FILES["file"]["size"];
        } else {
            $fileName = uniqid("file_");
        }
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            //-------------------------------------------------------
            //无论是什么文件名称，先unicode转utf8
            //unicode转utf8
            //注意$str='"..."'，内部双引号，外部单引号
            //对于变量$str='..'，我们需要处理'"'.$str.'"',处理后成一个新变量
            function unicode2utf8($str)
            {
                if (!$str) return $str;
                $decode = json_decode($str);
                if ($decode) return $decode;
                $str = '["' . $str . '"]';
                $decode = json_decode($str);
                if (count($decode) == 1) {
                    return $decode[0];
                }
                return $str;
            }

            $fileName = unicode2utf8('"' . $fileName . '"');
            $fileName = iconv("UTF-8", "GBK", $fileName);//防止fopen语句失效
            //-----------------------------------------------------------------------
        }

        $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
        $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;

        // 获取组块
        $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;  //分块
        $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1; //总共多少块

        // 删除旧的临时文件
        if ($cleanupTargetDir) {
            if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
            }
            while (($file = readdir($dir)) !== false) {
                $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
                //var_dump(file_exists("{$filePath}_{$chunk}.part"));die;
                // 如果临时文件是当前文件，则继续进行下一步
                if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
                    continue;
                }
                // 如果临时文件比最大文件大小，并且不是当前文件，则删除该文件
                if (preg_match('/\.(part|parttmp)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
                    @unlink($tmpfilePath);
                }
            }
            closedir($dir);
        }

        // 打开临时文件
        if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
        }

        if (!empty($_FILES)) {
            if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
            }

            // 读取二进制输入流并将其附加到临时文件
            if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
            }
        } else {
            if (!$in = @fopen("php://input", "rb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
            }
        }

        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }

        @fclose($out);
        @fclose($in);
        rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");

        $index = 0;
        $done = true;
        for ($index = 0; $index < $chunks; $index++) {
            if (!file_exists("{$filePath}_{$index}.part")) {
                $done = false;
                break;
            }
        }
        if ($done) {

            //上传成功的文件名自定义
            $data = input('post.');
            $pathInfo = pathinfo($fileName);
            $hashName = $pathInfo['basename'];
            $uploadPath = $uploadDir . DIRECTORY_SEPARATOR .$hashName;
            $fileSize = number_format($size/1048576,'2');
            $type = $data['type'];
            $file = $data['file'];
            $datas = [
                'name' => $hashName,
                'path' => $uploadPath,
                'size' => $fileSize,
                'type' => $type,
                'file' => $file,
            ];
            $upload = new UpModel($datas);
            $upload->allowField(true)->save();

            if (!$out = @fopen($uploadPath, "wb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
            }
            if (flock($out, LOCK_EX)) {
                for ($index = 0; $index < $chunks; $index++) {
                    if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
                        break;
                    }
                    while ($buff = fread($in, 4096)) {
                        fwrite($out, $buff);
                    }
                    @fclose($in);
                    @unlink("{$filePath}_{$index}.part");
                }
                flock($out, LOCK_UN);
            }
            @fclose($out);
        }
        // Return Success JSON-RPC response
        die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
    }
}